#ifndef GIFENCODER_H
#define GIFENCODER_H

#include "quantization/quantizer.h"
#include <QColor>
#include <QIODevice>
#include <QList>
#include <QObject>
#include <QRect>

// New gif encoder. Made by Nicke Manarin.

namespace WingGif {

enum class ColorQuantizationTypes {
  Neural = 0,
  Octree = 1,
  MedianCut = 2,
  Grayscale = 3,
  MostUsed = 4,
  Palette = 5,
};

class GifEncoder : public QObject {
  Q_OBJECT

  Q_PROPERTY(int repeatCount READ repeatCount WRITE setRepeatCount)
  Q_PROPERTY(bool useFullTransparency READ useFullTransparency WRITE
                 setUseFullTransparency)
  Q_PROPERTY(
      QColor transparentColor READ transparentColor WRITE setTransparentColor)
  Q_PROPERTY(int maximumNumberColor READ maximumNumberColor WRITE
                 setMaximumNumberColor)
  Q_PROPERTY(ColorQuantizationTypes quantizationType READ quantizationType WRITE
                 setQuantizationType)
  Q_PROPERTY(bool useGlobalColorTable READ useGlobalColorTable WRITE
                 setUseGlobalColorTable)
  Q_PROPERTY(int samplingFactor READ samplingFactor WRITE setSamplingFactor)

public:
  explicit GifEncoder(QIODevice *stream, QObject *parent = nullptr);
  ~GifEncoder();

  int repeatCount();
  bool setRepeatCount(int value);
  bool useFullTransparency();
  void setUseFullTransparency(bool value);
  QColor transparentColor();
  void setTransparentColor(QColor value);
  int maximumNumberColor();
  bool setMaximumNumberColor(int value);
  ColorQuantizationTypes quantizationType();
  void setQuantizationType(ColorQuantizationTypes value);
  bool useGlobalColorTable();
  void setUseGlobalColorTable(bool value);
  int samplingFactor();
  void setSamplingFactor(int value);

  void addFrame(QByteArray pixels, QRect rect, int delay = 66,
                bool isLastFrame = false);

private:
  void writeLogicalScreenDescriptor(QRect rect);
  void writePalette();
  void writeApplicationExtension();
  void writeGraphicControlExtension(int delay, bool isLastFrame);
  void writeImageDescriptor(QRect rect);
  void writeImage();

private:
  void readPixels(QByteArray pixels);

  void writeComment(QString comment);
  // Writes the comment for the animation.

  void calculateColorTableSize();

  int getMaximumColorCount();
  // Calculates the maximum number of colors for the
  // specified Logical Screen Description value.

  int findTransparentColorIndex();

private:
  int _repeatCount = 0;
  // Repeat Count for the gif.

  bool _useFullTransparency;
  // When enabled, the entire (star and end) gif will contain a transparent
  // background. Not related to the option to "paint unchanged pixels".

  QColor _transparentColor;
  // The color marked as transparent. Null if not in use.

  int _maximumNumberColor = 256;
  // The maximum number of colors of each frame of the gif.

  ColorQuantizationTypes _quantizationType = ColorQuantizationTypes::Octree;

  bool _useGlobalColorTable = false;
  // True if the gif should use a global color table instead of a local one.

  int _samplingFactor;

  QIODevice *internalStream = nullptr;
  // The stream which the gif is written on.

  bool isFirstFrame = false;
  // True if it's the first frame of the gif.

  QByteArray indexedPixels;
  // The list of indexed pixels, based on a color table (palette).

  QVector<QColor> colorTable;
  // The current color table. Global or local.

  bool colorTableHasTransparency;
  // True if the color table contains the color that will be treated as
  // transparent.

  int colorTableSize;
  // The size of the current color table.

  int OrganicTime;
  // Cumulative non adjusted time.

  int adjustedTime;
  // Adjusted and rounded off time.

  Quantizer *globalQuantizer;
  // If a quantizer needs to be constructed only once (for example, to use with
  // PaletteQuantizers), this property will be used.
};

} // namespace WingGif

#endif // GIFENCODER_H
